// run: $exec < input
// opt: 0
// flag: -g
#include <iostream>
#include <cstring>
#include <string>

int const maxn = 201000 * 4;
int const maxk = 12;
std::string s;
int n, m, k;

namespace segment_tree
{
	int sum[maxn][maxk][maxk];
	char left[maxn], right[maxn], cover[maxn];

	void cover_inter(int id, char c)
	{
		left[id] = right[id] = cover[id] = c;
		std::memset(sum[id], 0, sizeof(sum[id]));
	}

	void push_down(int id)
	{
		if (cover[id]) {
			cover_inter(id * 2, cover[id]);
			cover_inter(id * 2 + 1, cover[id]);
			cover[id] = 0;
		}
	}

	void push_up(int id)
	{
		for (int i = 0; i < k; i++)
			for (int j = 0; j < k; j++)
				sum[id][i][j] = sum[id * 2][i][j] + sum[id * 2 + 1][i][j];

		sum[id][right[id * 2] - 'a'][left[id * 2 + 1] - 'a']++;
		left[id] = left[id * 2];
		right[id] = right[id * 2 + 1];
	}

	void build(int id, int l, int r)
	{
		if (l == r) { left[id] = right[id] = s[l - 1]; return; }
		int mid = (l + r) / 2;
		build(id * 2, l, mid);
		build(id * 2 + 1, mid + 1, r);
		push_up(id);
	}

	void update(int id, int tl, int tr, char c, int l = 1, int r = n)
	{
		if (tl <= l && r <= tr) {
			cover_inter(id, c);
			return;
		}
		push_down(id);
		int mid = (l + r) / 2;
		if (tl <= mid) update(id * 2, tl, tr, c, l, mid);
		if (mid < tr) update(id * 2 + 1, tl, tr, c, mid + 1, r);

		push_up(id);
	}
};

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin >> n >> m >> k >> s;
	segment_tree::build(1, 1, n);
	for (int i = 0, op, l, r; i < m; i++) {
		std::cin >> op;
		if (op == 1) {
			char ch;
			std::cin >> l >> r >> ch;
			segment_tree::update(1, l, r, ch);
		} else {
			std::string str;
			std::cin >> str;
			int ans = n;
			for (int i = 0; i < k; i++)
				for (int j = i + 1; j < k; j++)
					ans -= segment_tree::sum[1][str[i] - 'a'][str[j] - 'a'];
			std::cout << ans << '\n';
		}
	}
}

